package com.fy.tt.service.impl;

import com.fy.tt.Executor;
import com.fy.tt.action.TemplateTool;
import com.fy.tt.dao.ScriptDao;
import com.fy.tt.entity.Script;
import com.fy.tt.entity.Semantic;
import com.fy.tt.entity.Word;
import com.fy.tt.entity.query.ScriptQuery;
import com.fy.tt.entity.vo.RunScriptVo;
import com.fy.tt.entity.vo.ScriptVo;
import com.fy.tt.parser.V3Lexer;
import com.fy.tt.parser.V3Parser;
import com.fy.tt.parser.Visitor;
import com.fy.tt.service.ScriptService;
import com.fy.tt.util.R;
import com.fy.tt.util.ThrowingErrorListener;
import com.fy.tt.util.TreeUtils;
import com.language.RunScript;
import com.language.parser.LanguageLexer;
import com.language.parser.LanguageParser;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenSource;
import org.antlr.v4.runtime.tree.ParseTree;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class ScriptServiceImpl implements ScriptService {
    Connection dbConnection = null;
    ScriptDao scriptDao = null;
    {
        try {
            dbConnection = TemplateTool.getDBConnection();
            scriptDao = TemplateTool.getBean(ScriptDao.class);
        }catch (Exception e){
            System.out.println(e.getCause());
            e.printStackTrace();
        }
    }

    @Override
    public List<ScriptVo> getAllScripts(){
        List<ScriptVo> scripts = null;
        try {
            scripts = scriptDao.getAllScripts(dbConnection);
        }catch (Exception e){

        }
        return scripts;
    }

    @Override
    public int getTotalScript(ScriptQuery scriptQuery) {
        int count = 0;
        try {
            count = scriptDao.getTotalScript(dbConnection, scriptQuery);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return count;
    }

    @Override
    public int addScript(Script script) {
        int i = 1;
        try {
            scriptDao.save(dbConnection, script);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return i;
    }

    @Override
    public int deleteScript(int id){
        int i = 0;
        try {
            i = scriptDao.deleteScript(dbConnection, id);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return i;
    }

    @Override
    public int updateScript(Script script){
        int i = 0;
        try {
            i = (int)scriptDao.updateIgnoreNull(dbConnection, script);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return i;
    }

    @Override
    public List<Script> getPageScripts(int pageSize, int current){
        List<Script> scripts = null;
        try {
            scripts = scriptDao.getPageScripts(dbConnection, pageSize, current);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return scripts;
    }

    @Override
    public List<ScriptVo> getConditionPageScripts(ScriptQuery scriptQuery, int pageSize, int current) {
        List<ScriptVo> scripts = null;
        try {
            scripts = scriptDao.getConditionPageScripts(dbConnection, scriptQuery, pageSize, current);
        }catch (Exception e){
            e.printStackTrace();
        }
        return scripts;
    }

    @Override
    public List<Semantic> getRelatedSemantic(int id){
        List<Semantic> semantics = null;
        try {
            semantics = scriptDao.getRelatedSemantic(dbConnection, id);
        }catch (Exception e){
            e.printStackTrace();
        }
        return semantics;
    }

    @Override
    public R runScript(List<RunScriptVo> scriptsList, int bandId) {
        int index = -1;
        RunScript runScript = new RunScript();
        R result = R.ok();
        try {
            for (RunScriptVo item : scriptsList) {
                index += 1;
                runScript.runScript(item.getScript(),"001",new HashMap<>(),"");
                result = result.put(item.getLine(), "试运行结果：" + item.getScript() + "在帮区" + bandId + "试运行成功");
            }
        }catch (Exception e){
            System.out.println(e.getMessage());
            return result.message("剧本试运行失败").put("errorLine",scriptsList.get(index).getLine()).put("log","xx节点试运行失败" + e.getCause());
        }
        return result.put("errorLine", -1).put("log","xx等节点试运行成功信息");
    }



    @Override
    public R deBugScript(List<RunScriptVo> scriptsList, int bandId) {
        int index = -1;
        RunScript runScript = new RunScript();
        R result = R.ok();
        try {
            for (RunScriptVo item : scriptsList) {
                index += 1;
                runScript.runScript(item.getScript(),"001",new HashMap<>(),"");
                result = result.put(item.getLine(), "调试结果：" + item.getScript() + "在帮区" + bandId + "调试成功");
            }
        }catch (Exception e){
            System.out.println(e.getMessage());
            return result.message("剧本调试失败").put("errorLine",scriptsList.get(index).getLine()).put("log","xx节点调试失败" + e.getCause());
        }
        return result.put("errorLine", -1).put("log","xx等节点调试成功信息");
    }

    @Override
    public R showAST(List<RunScriptVo> scriptsList, int bandId) {
        ParseTree parseTree = null;
        R result = R.ok();
        for (RunScriptVo item:scriptsList){
            String script = item.getScript();
            CommonTokenStream tokens = getCommonTokenStream(script.trim());
            LanguageParser parser = new LanguageParser(tokens);
            parser.removeErrorListeners();
            try {
                parser.addErrorListener(ThrowingErrorListener.INSTANCE);
                parseTree = parser.script();
                result.put(item.getLine(),TreeUtils.printSyntaxTree(parser, parseTree)) ;
            }catch (Exception e){
                return result.message("剧本解析语法树失败").put("errorLine",item.getLine()).put("log","剧本解析语法树失败" + e.getCause());
            }
        }
        return result.put("errorLine", -1).put("log","剧本解析语法树成功信息");
    }

    private CommonTokenStream getCommonTokenStream(String script){
        CharStream input = CharStreams.fromString(script);
        LanguageLexer lexer = new LanguageLexer(input);
        return new CommonTokenStream(lexer);
    }

 /*   @Override
    public R runScript(String script, int bandId) {
        System.out.println("------- jar完成  -------");
        String path = "Executor.jar";
        LoadJarUtil.loadJar(path);
        try {
            Class<?> aClass = Class.forName("com.language.RunScript");
            Object instance = aClass.newInstance();
            aClass.getDeclaredMethod("runScript",String.class,String.class, Map.class,String.class).invoke(instance,script,"001",new HashMap<>(),"");
        }catch (Exception e){
            System.out.println(e.getMessage());
            return R.error().message("剧本执行失败");
        }

        return R.ok().message("运行结果：" + script + "在帮区" + bandId + "执行成功");

    }*/

    /*@Override
    public R deBugScript(String script, int bandId) {
        System.out.println("------- jar完成  -------");
        String path = "G:\\test3\\Executor.jar";
        LoadJarUtil.loadJar(path);
        try {
            Class<?> aClass = Class.forName("com.language.RunScript");
            Object instance = aClass.newInstance();
            aClass.getDeclaredMethod("runScript",String.class,String.class, Map.class,String.class).invoke(instance,script,"001",new HashMap<>(),"");
        }catch (Exception e){
            System.out.println(e.getMessage());
            return R.error().message("剧本调试失败");
        }

        return R.ok().message("调试结果：" + script + "在帮区" + bandId + "调试成功");

    }

    @Override
    public String showAST(String script, int bandId) {
        String path = "G:\\test3\\Executor.jar";
        LoadJarUtil.loadJar(path);
        CommonTokenStream tokens = getCommonTokenStream(script.trim());
        System.out.println("-------------"+tokens.toString()+"-------------");
        try {
            Class<?> aClass = Class.forName("com.language.parser.LanguageParser");
            Constructor<?> constructor = aClass.getConstructor(TokenStream.class);
            Object parser = constructor.newInstance(tokens);
            // LanguageParser --> Parser ----> Recognizer
            aClass.getSuperclass().getSuperclass().getDeclaredMethod("removeErrorListeners").invoke(parser);
            aClass.getSuperclass().getSuperclass().getDeclaredMethod("addErrorListener",ANTLRErrorListener.class).invoke(parser, ThrowingErrorListener.INSTANCE);
            ParseTree parseTree = (ParseTree) aClass.getDeclaredMethod("script").invoke(parser);
            return TreeUtils.printSyntaxTree((Parser) parser, parseTree);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return "语法树解析异常";
    }*/

    @Override
    public R pushScript(int scriptId, int bandId) {
        List<Word> words = null;
        List<Semantic> semantics = null;
        try {
            words = scriptDao.getRelatedWord(dbConnection, scriptId);
            semantics = scriptDao.getRelatedSemantic(dbConnection, scriptId);
        }catch (Exception e){
            e.printStackTrace();
            return R.error().message("分享剧本失败");
        }
        return R.ok().message("分享剧本成功").put("words",words).put("semantics",semantics);
    }

    @Override
    public R pullScript(int scriptId, int bandId) {
        // 请求另一个机构的 pushScript,然后将返回结果存入本机构的数据库
        List<Word> words = null;
        List<Semantic> semantics = null;
        try {
            dbConnection.setAutoCommit(false);
            for(Word word:words){
//                wordDao.save(dbConnection, word);
            }
            for(Semantic semantic:semantics){
//                semanticDao.save(dbConnection, semantic);
            }
            dbConnection.commit();
        }catch (Exception e){
            e.printStackTrace();
            return R.error().message("应用剧本失败");
        }
        return R.ok().message("应用剧本成功");
    }

    @Override
    public List<ScriptVo> getLastSaveScript() {
        List<ScriptVo> allScripts = this.getAllScripts();
        List<ScriptVo> collect = allScripts.stream().sorted((a, b) -> {
            return (int) (b.getSaveTime().getTime() - a.getSaveTime().getTime());
        }).limit(5L).collect(Collectors.toList());
        return collect;
    }

    @Override
    public List<ScriptVo> getLastRunScript() {
        List<ScriptVo> allScripts = this.getAllScripts();
        List<ScriptVo> collect = allScripts.stream().sorted((a, b) -> {
            return (int) (b.getLastTime().getTime() - a.getLastTime().getTime());
        }).limit(5L).collect(Collectors.toList());
        return collect;
    }

   /* private CommonTokenStream getCommonTokenStream(String script){
        String path = "G:\\test3\\Executor.jar";
        LoadJarUtil.loadJar(path);
        CharStream input = CharStreams.fromString(script);
        try {
            Class<?> aClass = Class.forName("com.language.parser.LanguageLexer");
            Constructor<?> constructor = aClass.getConstructor(CharStream.class);
            Object o = constructor.newInstance(input);
            return new CommonTokenStream((TokenSource) o);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return null;
    }*/

    @Override
    public R runScriptTest(List<RunScriptVo> scriptsList, int bandId, int scriptId) {
        int index = -1;
        Executor executor = new Executor();
        R result = R.ok();
        try {
            for (RunScriptVo item : scriptsList) {
                index += 1;
                executor.runScript(item.getScript(),new HashMap<>(),scriptId);
                result = result.put(item.getLine(), "试运行结果：" + item.getScript() + "在帮区" + bandId + "试运行成功");
            }
        }catch (Exception e){
            System.out.println(e.getMessage());
            return result.message("剧本试运行失败").put("errorLine",scriptsList.get(index).getLine()).put("log","xx节点试运行失败" + e.getCause());
        }
        return result.put("errorLine", -1).put("log","xx等节点试运行成功信息");
    }

    @Override
    public R deBugScriptTest(List<RunScriptVo> scriptsList, int bandId, int scriptId) {
        int index = -1;
        Executor executor = new Executor();
        R result = R.ok();
        try {
            for (RunScriptVo item : scriptsList) {
                index += 1;
                executor.runScript(item.getScript(),new HashMap<>(),scriptId);
                result = result.put(item.getLine(), "调试结果：" + item.getScript() + "在帮区" + bandId + "调试成功");
            }
        }catch (Exception e){
            System.out.println(e.getMessage());
            return result.message("剧本调试失败").put("errorLine",scriptsList.get(index).getLine()).put("log","xx节点调试失败" + e.getCause());
        }
        return result.put("errorLine", -1).put("log","xx等节点调试成功信息");
    }

    @Override
    public R showASTTest(List<RunScriptVo> scriptsList, int bandId) {
        ParseTree parseTree = null;
        R result = R.ok();
        for (RunScriptVo item:scriptsList){
            String script = item.getScript();
            V3Parser parser = getParser(script.trim());
            parser.removeErrorListeners();
            try {
                parser.addErrorListener(ThrowingErrorListener.INSTANCE);
                parseTree = parser.script();
                result.put(item.getLine(),TreeUtils.printSyntaxTree(parser, parseTree)) ;
            }catch (Exception e){
                return result.message("剧本解析语法树失败").put("errorLine",item.getLine()).put("log","剧本解析语法树失败" + e.getCause());
            }
        }
        return result.put("errorLine", -1).put("log","剧本解析语法树成功信息");
    }

    private V3Parser getParser(String script){
        CharStream input = CharStreams.fromString(script);
        V3Lexer lexer = new V3Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        V3Parser parser = new V3Parser(tokens);
        return parser;
    }
}
